package demo8;


// 死锁：
// 1. 互斥使用(锁的特性) ：当 锁locker 已经被线程一上锁后，后面的线程想使用 锁locker ，就得阻塞等待
// 2. 不可抢占(锁的特性) ： 当锁locker 已经被线程一上锁后，后面的线程不能抢占，只能等待线程一主动释放后在进行加锁
// 3. 保持请求： 当某个线程对多个锁进行嵌套加锁时候，其他锁并不解锁，而是保持 加锁的状态
// 4. 循环等待/环路等待
public class Test17 {
    static Object locker1=new Object();
    static Object locker2=new Object();

    public static void main01(String[] args) {
        Thread t1=new Thread(()->{
            synchronized(locker1){
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                synchronized (locker2){
                        System.out.println("locker1 加锁成功！");
                }

            }
        });
        Thread t2=new Thread(()->{
            synchronized(locker2){
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                synchronized (locker1){
                        System.out.println("locker2 加锁成功！");
                }

            }
        });

        t1.start();
        t2.start();
        System.out.println(" 完毕！！");
        // 当我们这样加锁时，t1线程首先对locker1进行加锁 ， 而t2线程对locker2进行加锁
        // 当t1在想对locker2进行加锁的时候，由于locker2已经被锁起来，导致t1线程变成阻塞状态，等待t2 线程释放locker2
        // 而t2 又在等t1释放锁locker1，这样就形成了“死锁”
    }


    // 那我们如何解决死锁的问题呢：
    // 我们可以对所有线程都采取 先对所有锁进行编号，然后优先对编号小的锁进行 加锁
    public static void main(String[] args) throws InterruptedException {
        Thread t1=new Thread(()->{
            synchronized(locker1){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                synchronized (locker2){
                    System.out.println("locker1 加锁成功！");
                }

            }
        });
        Thread t2=new Thread(()->{
            synchronized(locker1){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                synchronized (locker2){
                    System.out.println("locker2 加锁成功！");
                }

            }
        });

        t1.start();
        t2.start();

        Thread.sleep(3000);
        System.out.println(" 完毕！！");
    }
}
